package com.niiwoo.civet.mobile.controller.lanmao;

import com.alibaba.dubbo.common.URL;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.niiwoo.civet.mobile.lanmao.handler.HandleResult;
import com.niiwoo.civet.mobile.lanmao.handler.LanMaoNotifyHandler;
import com.niiwoo.tripod.base.annotation.ProfileSpecified;
import com.niiwoo.tripod.base.serializer.Number2StringFilter;
import com.niiwoo.tripod.lanmao.component.LanMaoSignature;
import com.niiwoo.tripod.lanmao.response.LanMaoNotifyResponse;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.web.annotation.AuthIgnore;
import com.niiwoo.tripod.web.vo.Error;
import com.niiwoo.tripod.web.vo.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Optional;

/**
 * Created by zhangwanli on 2017/11/9.
 */
@Controller
@RequestMapping("/lanmao")
@ProfileSpecified
@Profile({"experience", "production"})
@AuthIgnore
@Api(hidden = true)
public class LanMaoNotifyDispatchController {
    private static final Logger logger = LoggerFactory.getLogger(LanMaoNotifyDispatchController.class);

    @Autowired
    private List<LanMaoNotifyHandler> handlers;

    @Autowired
    private LanMaoSignature signature;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private ValueFilter filter = new Number2StringFilter();


    @RequestMapping("/notify")
    @ApiOperation(value = "懒猫异步通知接收", hidden = true)
    @ResponseBody
    public String receiveNotify(LanMaoNotifyResponse notifyResponse, HttpServletResponse servletResponse) throws Exception {
        HandleResult handleResult = null;
        try {
            handleResult = this.handle(notifyResponse);
        } catch (BizException e) {
            return "FAILURE";
        } catch (Exception e) {
            return "FAILURE";
        }
        return handleResult.getNeedAck() ? "SUCCESS" : "FAILURE";
    }

    @RequestMapping("/callback")
    @ApiOperation(value = "懒猫异步通知接收", hidden = true)
    public ModelAndView receiveCallback(LanMaoNotifyResponse notifyResponse, HttpServletResponse response) throws Exception {
        //TODO 判断redis redirectUrl区分H5和APP,目前只考虑APP情况
        HandleResult handleResult = new HandleResult();
        ModelAndView view = new ModelAndView("redirect");

        try {
            handleResult = this.handle(notifyResponse);
            view.addObject("result", JSON.toJSONString(Result.with(handleResult.getData()), filter));
        } catch (BizException e) {
            logger.error("lanmao callback 处理异常", e);
            Error error = new Error(e.getErrorCode(), e.getMessage());
            view.addObject("result", JSON.toJSONString(error));
        } catch (Exception e) {
            logger.error("lanmao callback 处理异常", e);
            Error error = new Error("SYS9999", "系统异常");
            view.addObject("result", JSON.toJSONString(error));
        }
        String h5RedirectUrl = Optional.ofNullable(handleResult)
                .filter(r -> StringUtils.isNotBlank(r.getRequestNo()))
                .map(r -> redisTemplate.opsForValue().get(r.getRequestNo()))
                .orElse(null);
        logger.info("懒猫同步通知接收###H5缓存重定向地址={}", h5RedirectUrl);
        if (StringUtils.isNotBlank(h5RedirectUrl)) {
            String serverParamKey = "serverResp";
            String serverParamValue = Optional.ofNullable(handleResult)
                    .map(HandleResult::getData)
                    .map(d -> {
                        try {
                            return URLEncoder.encode(JSON.toJSONString(d, filter), "UTF-8");
                        } catch (UnsupportedEncodingException e) {
                            logger.error("懒猫同步通知接收###H5重定向编码错误", e);
                            return "";
                        }
                    })
                    .orElse("");
            final String finalRedirctUrl;
            boolean hasParams = Optional.ofNullable(URL.valueOf(h5RedirectUrl).getParameters()).filter(paramMap -> !paramMap.isEmpty()).isPresent();
            if (hasParams) {
                finalRedirctUrl = String.format("redirect:%s&%s=%s", h5RedirectUrl, serverParamKey, serverParamValue);
            } else {
                finalRedirctUrl = String.format("redirect:%s?%s=%s", h5RedirectUrl, serverParamKey, serverParamValue);
            }
            logger.info("懒猫同步通知接收###H5最终重定向={}", finalRedirctUrl);
            return new ModelAndView(finalRedirctUrl);
        }
        return view;
    }

    private HandleResult handle(LanMaoNotifyResponse notifyResponse) {
        String serviceName = notifyResponse.getServiceName();
        String respData = notifyResponse.getRespData();
        String sign = notifyResponse.getSign();
        HandleResult handleResult = new HandleResult();
        handleResult.setNeedAck(false);//初始化不应答
        Boolean verify = signature.verify(sign, respData);
        if (!verify) {
            logger.error("验签存管页面通知失败,serviceName={}", serviceName);
            return handleResult;
        }

        Boolean handled = false;
        for (LanMaoNotifyHandler handler : handlers) {
            if (handler.supports(serviceName)) {
                logger.info("found LanMaoNotifyHandler: {} for {}", handler.getClass().getName(), serviceName);
                handleResult = handler.handle(JSON.parseObject(respData));
                handled = true;
                break;
            }
        }
        if (!handled) {
            logger.error("未找到处理存管页面通知的handler,serviceName={}", serviceName);
        }
        return handleResult;
    }

}
